package com.suning.sawp.service.impl.task;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.joda.time.LocalDate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.common.base.Function;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimaps;
import com.suning.framework.dal.client.DalClient;
import com.suning.sawp.dto.mainpush.TaskStoreTempDto;
import com.suning.sawp.intf.dao.task.TaskStoreAndClerkDaoService;
import com.suning.sawp.po.bi.BIStaffPushCommMonth;
import com.suning.sawp.po.mainpush.CommTaskClerk;
import com.suning.sawp.po.mainpush.MainPushTask;
import com.suning.sawp.po.task.TaskClerk;
import com.suning.sawp.service.task.dto.BIStoreTask;
import com.suning.sawp.service.task.dto.BIStoreTaskComm;
import com.suning.sawp.service.task.dto.SaleCompletion;

/**
 * 
 * 门店BI统计数据展示服务
 * 
 * @author 13071602
 *
 */
@Service
public class StoreTaskBIShowService {

    private static final Logger LOGGER = LoggerFactory.getLogger(StoreTaskBIShowService.class);
    @Autowired
    DalClient dalClient;

    @Resource
    TaskStoreAndClerkDaoService taskStoreAndClerkDaoService;

    /**
     * 根据品类编码查询 活动的主推
     * 
     * @param cateCode 品类编码
     * 
     * @see sqlMap_StoreTaskBIShow.xml
     */
    public TaskStoreTempDto queryActiveTaskByCateCode(String cateCode, String storeCode) {
        Map<String, Object> paramMap = Maps.newHashMap();
        paramMap.put("cateCode", cateCode);
        paramMap.put("storeCode", storeCode);
        TaskStoreTempDto storeTask = dalClient.queryForObject("StoreTaskBIShow.queryActiveTaskByCateCode", paramMap,
                TaskStoreTempDto.class);
        return storeTask;
    }

    public TaskStoreTempDto queryTaskStoreByTaskNo(Long taskNo) {
        Map<String, Object> paramMap = Maps.newHashMap();
        paramMap.put("taskNo", taskNo);
        TaskStoreTempDto storeTask = dalClient.queryForObject("StoreTaskBIShow.queryTaskStoreByTaskNo", paramMap,
                TaskStoreTempDto.class);
        return storeTask;
    }

    /**
     * 展示总部任务
     * 
     * @see sqlMap_StoreTaskBIShow.xml
     * 
     * @param taskNo 门店任务编号
     */
    public BIStoreTask queryStoreTask(TaskStoreTempDto taskStore) {
        BIStoreTask storeTask = new BIStoreTask();
        storeTask.setStartTime(taskStore.getStartTime());
        storeTask.setEndTime(taskStore.getEndTime());
        storeTask.setTaskNo(taskStore.getTaskNo());
        Map<String, Object> paramMap = Maps.newHashMap();
        final Long taskNo = taskStore.getTaskNo();
        paramMap.put("taskNo", taskNo);
        // 统计当前月份
        paramMap.put("saleMonth", new LocalDate().toString("yyyyMM"));
        // 商品BI统计
        List<BIStoreTaskComm> origTaskComms = dalClient.queryForList("StoreTaskBIShow.queryTaskComm", paramMap,
                BIStoreTaskComm.class);
        List<BIStoreTaskComm> taskComms = new ArrayList<BIStoreTaskComm>();
        List<BIStoreTaskComm> tmpComms = new ArrayList<BIStoreTaskComm>();
        for (BIStoreTaskComm comm : origTaskComms) {
            if (MainPushTask.CommodityStatusConstants.DEL_READ.equals(String.valueOf(comm.getCommStatus()))
                    || MainPushTask.CommodityStatusConstants.NOT_DELETE.equals(String.valueOf(comm.getCommStatus()))) {
                // 产品要求删除未阅要置于前面展示
                tmpComms.add(comm);
            } else {
                // 其他商品状态的放在tmpComms列表中
                taskComms.add(comm);
            }
        }
        // 组合两组列表数据taskComms、tmpComms
        taskComms.addAll(tmpComms);
        class ReduceSum implements Function<List<BIStoreTaskComm>, SaleCompletion> {
            // XXX 销售总额有冲突，这边直接明细汇
            BigDecimal saleAmount = new BigDecimal("0.00");

            @Override
            public SaleCompletion apply(List<BIStoreTaskComm> comms) {
                SaleCompletion completion = new SaleCompletion();
                int destNum = 0;// 目标销售总台数
                int completionNum = 0;// 销售完成台数
                for (BIStoreTaskComm comm : comms) {
                    // 该商品类型总计
                    destNum += comm.getDestNum();
                    if (null != comm.getUpdateTime()) {
                        saleAmount = saleAmount.add(comm.getSaleAmount());
                        // 该商品类型总计
                        completionNum += comm.getSaleVolume();
                        // 该商品统计
                        comm.setCompletionRate(BigDecimal
                                .valueOf(comm.getDestNum() == 0 ? 0 : (1.0 * comm.getSaleVolume() / comm.getDestNum()))
                                .setScale(2, BigDecimal.ROUND_HALF_UP));
                    } else {
                        LOGGER.warn("{} of task {} 无销售统计数据", taskNo, comm.getCommName());
                    }
                }
                completion.setDestNum(destNum);
                completion.setCompletionNum(completionNum);
                return completion;
            }
        }
        ReduceSum reduceSum = new ReduceSum();
        Map<String, SaleCompletion> recuduceMap = Maps
                .transformValues(Multimaps.asMap(Multimaps.index(taskComms, new Function<BIStoreTaskComm, String>() {
                    @Override
                    public String apply(BIStoreTaskComm comm) {
                        return comm.getCommType();
                    }
                })), reduceSum);
        // 任务完成率
        SaleCompletion completionA = recuduceMap.get("A");
        SaleCompletion completionB = recuduceMap.get("B");
        storeTask.setCompletionRate(BigDecimal
                .valueOf(0.6
                        * (null != completionA && completionA.getDestNum() > 0
                                ? completionA.getCompletionNum() * 1.0 / completionA.getDestNum() : 0)
                + 0.4 * (null != completionB && completionB.getDestNum() > 0
                        ? completionB.getCompletionNum() * 1.0 / completionB.getDestNum() : 0))
                .setScale(2, RoundingMode.CEILING));
        storeTask.setSaleAmount(reduceSum.saleAmount);
        storeTask.setComms(taskComms);
        // 若存在新增、变更、删除未阅状态，变更状态
        updateStoreTaskCommStatus(taskComms, taskNo);

        return storeTask;
    }

    public BIStoreTask queryClerkTask(TaskClerk taskClerk, String staffId) {
        BIStoreTask completeDto = new BIStoreTask();
        completeDto.setStartTime(taskClerk.getStartTime());
        completeDto.setEndTime(taskClerk.getEndTime());
        Long taskNo = taskClerk.getTaskNo();
        Map<String, Object> paramMap = Maps.newHashMap();
        paramMap.put("taskNo", taskNo);
        List<CommTaskClerk> comms = dalClient.queryForList("STORE_MAIN_PUSH.QUERY_CLERK_TASK_COMMS", paramMap,
                CommTaskClerk.class);
        Set<Integer> unicodes = new HashSet<Integer>();
        List<Map<String, Object>> mapList = new ArrayList<Map<String, Object>>();
        for (CommTaskClerk comm : comms) {
            unicodes.add(comm.getCommClassifyCode());
            Map<String, Object> updateParamMap = getUpdateCommMap(comm, taskNo);
            if (null != updateParamMap) {
                mapList.add(updateParamMap);
            }
        }
        // 取对应的总部任务编号
        Long hqTaskNo = taskStoreAndClerkDaoService.queryHqTaskNo(taskNo, MainPushTask.OrgLevelConstants.LEVEL_CLERK);
        // 取BI店员该任务统计详情
        paramMap.clear();
        paramMap.put("taskNo", hqTaskNo);
        paramMap.put("staffId", staffId);
        paramMap.put("uniCodes", unicodes);
        List<BIStaffPushCommMonth> biComms = dalClient.queryForList("STORE_MAIN_PUSH.QUERY_BI_CLERK_TASK_COMMS",
                paramMap, BIStaffPushCommMonth.class);
        List<BIStoreTaskComm> taskComms = new ArrayList<BIStoreTaskComm>();
        List<BIStoreTaskComm> tmpComms = new ArrayList<BIStoreTaskComm>();
        for (CommTaskClerk comm : comms) {
            BIStoreTaskComm taskComm = new BIStoreTaskComm();
            taskComm.setCommName(comm.getCommName());
            taskComm.setCommStatus(comm.getCommStatus());
            taskComm.setCommType(comm.getCommType());
            taskComm.setDestNum(comm.getDestNum());
            taskComm.setSaleVolume(0);
            for (BIStaffPushCommMonth biComm : biComms) {
                if (comm.getCommClassifyCode().equals(biComm.getModelId())) {
                    taskComm.setSaleVolume(biComm.getSaleVolume());
                }
            }
            if (MainPushTask.CommodityStatusConstants.DEL_READ.equals(String.valueOf(comm.getCommStatus()))
                    || MainPushTask.CommodityStatusConstants.NOT_DELETE.equals(String.valueOf(comm.getCommStatus()))) {
                // 产品要求删除未阅要置于前面展示
                tmpComms.add(taskComm);
            } else {
                // 其他商品状态的放在tmpComms列表中
                taskComms.add(taskComm);
            }
        }
        // 组合两组列表数据taskComms、tmpComms
        taskComms.addAll(tmpComms);
        int commAsaleVolume = 0;
        int commAdestNum = 0;
        int commBsaleVolume = 0;
        int commBdestNum = 0;
        for (BIStoreTaskComm taskComm : taskComms) {
            if ("A".equals(taskComm.getCommType())) {
                commAsaleVolume += taskComm.getSaleVolume();
                commAdestNum += taskComm.getDestNum();
            }
            if ("B".equals(taskComm.getCommType())) {
                commBsaleVolume += taskComm.getSaleVolume();
                commBdestNum += taskComm.getDestNum();
            }
        }

        double totalCompleteRate = (commAdestNum == 0 ? 0.0d
                : ((double) commAsaleVolume / commAdestNum) * 0.6) + (commBdestNum == 0 ? 0.0d
                        : ((double) commBsaleVolume / commBdestNum) * 0.4);
        completeDto.setCompletionRate(BigDecimal.valueOf(totalCompleteRate));
        completeDto.setComms(taskComms);
        // 更新商品状态
        if (CollectionUtils.isNotEmpty(mapList)) {
            @SuppressWarnings("unchecked")
            Map<String, Object>[] batchValues = (Map<String, Object>[]) mapList.toArray(new Map[mapList.size()]);
            dalClient.batchUpdate("STORE_MAIN_PUSH.UPDATE_COMM_CLERK_TASK_COMM_STATUS", batchValues);
        }
        return completeDto;
    }

    /**
     * 
     * 功能描述: 变更商品状态<br>
     * 〈功能详细描述〉 （新增、变更）-> 正常，删除未阅->删除已阅
     * 
     * @param taskComms
     * @param taskNo
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    private void updateStoreTaskCommStatus(List<BIStoreTaskComm> taskComms, Long taskNo) {
        int newCommStatus = Integer.parseInt(MainPushTask.CommodityStatusConstants.NEW);
        int updateCommStatus = Integer.parseInt(MainPushTask.CommodityStatusConstants.MODIFIED);
        int delNoReadCommStatus = Integer.parseInt(MainPushTask.CommodityStatusConstants.DEL_NO_READ);
        int delCommStatus = Integer.parseInt(MainPushTask.CommodityStatusConstants.DEL_READ);
        int normalCommStatus = Integer.parseInt(MainPushTask.CommodityStatusConstants.NOT_DELETE);
        List<Map<String, Object>> mapList = new ArrayList<Map<String, Object>>();
        for (BIStoreTaskComm comm : taskComms) {
            if (newCommStatus == comm.getCommStatus() || updateCommStatus == comm.getCommStatus()) {
                // 商品状态为新增或者修改，查询之后更改状态为正常状态
                Map<String, Object> paramMap = new HashMap<String, Object>();
                paramMap.put("taskNo", taskNo);
                paramMap.put("uniCode", comm.getUniCode());
                paramMap.put("commStatus", normalCommStatus);
                mapList.add(paramMap);
            } else if (delNoReadCommStatus == comm.getCommStatus()) {
                // 商品状态为删除未阅，查询之后更改状态为删除已阅
                Map<String, Object> paramMap = new HashMap<String, Object>();
                paramMap.put("taskNo", taskNo);
                paramMap.put("uniCode", comm.getUniCode());
                paramMap.put("commStatus", delCommStatus);
                mapList.add(paramMap);
            }
        }

        if (CollectionUtils.isNotEmpty(mapList)) {
            // 更新DB状态
            @SuppressWarnings("unchecked")
            Map<String, Object>[] batchValues = (Map<String, Object>[]) mapList.toArray(new Map[mapList.size()]);
            dalClient.batchUpdate("STORE_MAIN_PUSH.UPDATE_COMM_STORE_TASK_COMM_STATUS", batchValues);
        }
    }

    /**
     * 
     * 功能描述: 获取商品状态变更的参数MAP<br>
     * 〈功能详细描述〉
     *
     * @param comm
     * @param taskNo
     * @return
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    private Map<String, Object> getUpdateCommMap(CommTaskClerk comm, Long taskNo) {
        int newCommStatus = Integer.parseInt(MainPushTask.CommodityStatusConstants.NEW);
        int updateCommStatus = Integer.parseInt(MainPushTask.CommodityStatusConstants.MODIFIED);
        int delNoReadCommStatus = Integer.parseInt(MainPushTask.CommodityStatusConstants.DEL_NO_READ);
        int delCommStatus = Integer.parseInt(MainPushTask.CommodityStatusConstants.DEL_READ);
        int normalCommStatus = Integer.parseInt(MainPushTask.CommodityStatusConstants.NOT_DELETE);
        Map<String, Object> paramMap = null;
        if (newCommStatus == comm.getCommStatus() || updateCommStatus == comm.getCommStatus()) {
            // 商品状态为新增或者修改，查询之后更改状态为正常状态
            paramMap = new HashMap<String, Object>();
            paramMap.put("taskNo", taskNo);
            paramMap.put("uniCode", comm.getCommClassifyCode());
            paramMap.put("commStatus", normalCommStatus);
        } else if (delNoReadCommStatus == comm.getCommStatus()) {
            // 商品状态为删除未阅，查询之后更改状态为删除已阅
            paramMap = new HashMap<String, Object>();
            paramMap.put("taskNo", taskNo);
            paramMap.put("uniCode", comm.getCommClassifyCode());
            paramMap.put("commStatus", delCommStatus);
        }

        return paramMap;
    }
}
